using System;
using System.Collections.Generic;
using UnityEngine;

namespace Framework
{
    public class InputDeviceManager
    {
        public Action<InputDevice> OnDeviceConnected;
        public Action<InputDevice> OnDeviceDisConnected;

        public int DeviceCount { get; private set; }
        private readonly Dictionary<int, InputDevice> devices;
        private Dictionary<int, InputDevice> connectedDevices;
        private Queue<InputDevice> addList;
        private Queue<InputDevice> removeList;
        private List<InputDevice> deviceList;
        private bool _dirty;
        private InputContext _context;

        public InputDeviceManager()
        {
            _context = new InputContext();
            devices = new Dictionary<int, InputDevice>();
            connectedDevices = new Dictionary<int, InputDevice>();
            addList = new Queue<InputDevice>();
            removeList = new Queue<InputDevice>();
            deviceList = new List<InputDevice>();
        }
        public void AddActionCallback(IActionInputCallback value)
        {
            _context.AddCallback(value);
        }
        public void RemoveActionCallback(IActionInputCallback value)
        {
            _context.RemoveCallback(value);
        }
        public T AddInteraction<T>(string name) where T : VirtualInteraction, new()
        {
            var value = new T();
            _context.AddInteraction(name, value);
            return value;
        }
        public void RemoveInteraction(string name, VirtualInteraction value)
        {
            _context.RemoveInteraction(name, value);
        }
        public InputDevice GetItem(int index)
        {
            if (index < 0 || deviceList.Count < 1 || index >= deviceList.Count)
            {
                return null;
            }
            return deviceList[index];
        }
        public void ClearDevice()
        {
            foreach (var item in devices)
            {
                if (item.Value.IsVirtual)
                {
                    continue;
                }
                item.Value.Active = false;
            }
            _dirty = true;
        }
        public InputDevice AddDevice(int deviceId, string name = null)
        {
            _dirty = true;
            if (!devices.TryGetValue(deviceId, out var device))
            {
                device = new InputDevice(deviceId);
                device._context = _context;
                devices.Add(deviceId, device);
            }
            device.Active = true;
            return device;
        }
        public InputDevice GetDevice(int deviceId)
        {
            //UnityEngine.InputSystem.InputAction.CallbackContext obj
            //obj.control.device.deviceId
            if (devices.TryGetValue(deviceId, out var device))
            {
                return device;
            }
            return null;
        }
        public void Update(float deltaTime)
        {
            if (_dirty)
            {
                deviceList.Clear();
                foreach (var item in devices)
                {
                    if (item.Value.Active)
                    {
                        deviceList.Add(item.Value);
                        if (!connectedDevices.ContainsKey(item.Value.DeviceID))
                        {
                            addList.Enqueue(item.Value);
                            connectedDevices.Add(item.Value.DeviceID, item.Value);
                        }
                    }
                    else
                    {
                        if (connectedDevices.ContainsKey(item.Value.DeviceID))
                        {
                            removeList.Enqueue(item.Value);
                            connectedDevices.Remove(item.Value.DeviceID);
                        }
                    }
                }
                DeviceCount = connectedDevices.Count;
                while (addList.Count > 0)
                {
                    var item = addList.Dequeue();
                    OnDeviceConnected?.Invoke(item);

                }
                while (removeList.Count > 0)
                {
                    var item = removeList.Dequeue();
                    OnDeviceDisConnected?.Invoke(item);
                }
            }
            var len = deviceList.Count;
            while (len-- > 0)
            {
                deviceList[len].Update(deltaTime);
            }
            _context.Update(deltaTime);
        }
    }

    internal class InputContext
    {
        private readonly List<IActionInputCallback> _callbacks;
        private List<IActionInputCallback> _callbacksTemp;
        private readonly Dictionary<string, List<VirtualInteraction>> _interactionSetting;
        private List<VirtualInteraction> _interactions;
        private List<InputAction> _holdActions;
        public InputContext()
        {
            _callbacks = new List<IActionInputCallback>();
            _interactionSetting = new Dictionary<string, List<VirtualInteraction>>();
            _interactions = new List<VirtualInteraction>();
            _callbacksTemp = new List<IActionInputCallback>();
            _holdActions = new List<InputAction>();
        }
        public void AddCallback(IActionInputCallback value)
        {
            if (_callbacks.Contains(value))
            {
                return;
            }
            _callbacks.Add(value);
            if (_callbacks.Count > 5)
            {
                Debug.LogError("检查功能实现是否合理");
            }
        }
        public void RemoveCallback(IActionInputCallback value)
        {
            _callbacks.Remove(value);
        }
        public void AddInteraction(string name, VirtualInteraction value)
        {
            if (!_interactionSetting.TryGetValue(name, out var list))
            {
                list = new List<VirtualInteraction>();
                _interactionSetting.Add(name, list);
            }
            var len = list.Count;
            while (len-- > 0)
            {
                var item = list[len];
                if (value.GetType().Equals(item.GetType()))
                {
                    list.RemoveAt(len);
                }
            }
            list.Add(value);
        }
        public void RemoveInteraction(string name, VirtualInteraction value)
        {
            if (!_interactionSetting.TryGetValue(name, out var list))
            {
                return;
            }
            var len = list.Count;
            while (len-- > 0)
            {
                var item = list[len];
                if (value.GetType().Equals(item.GetType()))
                {
                    list.RemoveAt(len);
                }
            }
            if (list.Count < 1)
            {
                _interactionSetting.Remove(name);
            }
        }
        private float GetHoldIntervalTime(string actionName)
        {
            return 0f;
        }
        private void OnActionInputStart(InputAction action)
        {
            _callbacksTemp.Clear();
            _callbacksTemp.AddRange(_callbacks);
            foreach (var item in _callbacksTemp)
            {
                item.OnActionInputStart(action);
            }

            action._holdIntervalTime = GetHoldIntervalTime(action.name);
            if (action._holdIntervalTime > 0)
            {
                _holdActions.Add(action);
            }
        }
        private void OnActionInputPerform(InputAction action)
        {
            _callbacksTemp.Clear();
            _callbacksTemp.AddRange(_callbacks);

            foreach (var item in _callbacksTemp)
            {
                item.OnActionInputPerform(action);
            }
        }
        private void OnActionInputCancel(InputAction action)
        {
            _callbacksTemp.Clear();
            _callbacksTemp.AddRange(_callbacks);
            foreach (var item in _callbacksTemp)
            {
                item.OnActionInputCancel(action);
            }
        }
        private void OnActionHoldPerform(InputAction action)
        {
            _callbacksTemp.Clear();
            _callbacksTemp.AddRange(_callbacks);
            foreach (var item in _callbacksTemp)
            {
                item.OnActionHoldPerform(action);
            }
        }
        internal void InputStart(InputAction action)
        {
            OnActionInputStart(action);
            if (!action.device.IsVirtual)
            {
                return;
            }
            if (action._interactions.Count < 1)
            {
                if (_interactionSetting.TryGetValue(action.name, out var list))
                {
                    var len = list.Count;
                    while (len-- > 0)
                    {
                        var t = list[len];
                        var v = t.Clone();
                        v.Action = action;
                        action._interactions.Add(v);

                    }
                }
            }
            foreach (var item in action._interactions)
            {
                item.Start();
                _interactions.Add(item);
            }
        }
        internal void InputPerform(InputAction action)
        {
            if (!action.device.IsVirtual)
            {
                OnActionInputPerform(action);
                return;
            }
            if (action._interactions.Count < 1)
            {
                OnActionInputPerform(action);
                return;
            }
        }
        internal void InputCancel(InputAction action)
        {
            if (!action.device.IsVirtual)
            {
                OnActionInputCancel(action);
                return;
            }
            if (action._interactions.Count < 1)
            {
                OnActionInputCancel(action);
                return;
            }
            foreach (var item in action._interactions)
            {
                item.Stop();
            }
        }
        public void Update(float deltaTime)
        {
            var len = _interactions.Count;
            while (len-- > 0)
            {
                var item = _interactions[len];
                item.Update(deltaTime);
                if (item.NeedPerform())
                {
                    item.Action._interactionType = item.InteractionType;
                    OnActionInputPerform(item.Action);
                    item.Action._interactionType = InteractionType.None;
                }
                if (item.NeedCancel())
                {
                    item.Action._interactionType = item.InteractionType;
                    OnActionInputCancel(item.Action);
                    item.Action._interactionType = InteractionType.None;
                }
                if (item.IsFinished())
                {
                    item.Dispose();
                    _interactions.RemoveAt(len);
                }
            }
            len = _holdActions.Count;
            while ((len-- > 0))
            {
                var action = _holdActions[len];
                if (!action._active)
                {
                    _holdActions.RemoveAt(len);
                    continue;
                }
                if (action.UpdateHold(deltaTime))
                {
                    OnActionHoldPerform(action);
                }
            }
        }
    }
    public enum InputDeviceType
    {
        None = 0,
        Keyboard, // 键盘
        Touch, // 触屏设备
        Gamepad,//手柄
    }
    public enum InputDeviceName
    {
        None = 0,
        Keyboard, // 键盘
        Touch, // 触屏设备
        Xbox, // Xbox Joystick
        PlayStation, // PlayStation Joystick
        Switch, // Nintendo
    }
    internal class InputDeviceFlag
    {
        public const string Mouse = "Mouse";
        public const string Touch = "Touch";
        public const string Keyboard = "Keyboard";
        public const string XInput = "XInput"; // 微软系手柄
        public const string DualShock = "Dual"; // 索尼系手柄
        public const string NPad = "NPad"; // 任天堂系手柄
    }
    public class InputDevice
    {
        public readonly int DeviceID;
        public string Name { get { return _name; } }
        internal bool Active;
        public bool IsVirtual { get; private set; }
        public InputDeviceType DeviceType { get; private set; }
        public InputDeviceName DeviceName { get; private set; }
        private Dictionary<string, InputAction> actions;
        internal string _name;
        internal InputContext _context;
        public InputDevice(int id)
        {
            this.DeviceID = id;
            actions = new Dictionary<string, InputAction>();
        }
        public void SetVirtual(bool value = true)
        {
            IsVirtual = value;
        }
        public void SetName(string name)
        {
            DeviceName = GetDeviceName(name);
            DeviceType = GetDeviceType(DeviceName);
        }
        public void SetValue(string name, float value = 1f, float value2 = 0f, float value3 = 0f)
        {
            var action = GetAction(name, true);
            action._value = value;
            action._value2 = new Vector2(value, value2);
            action._value3 = new Vector3(value, value2, value3);
        }
        public void Start(string name, InteractionType interactionType = InteractionType.None)
        {
            var action = GetAction(name, true);
            action._interactionType = interactionType;
            action.Start();
            _context.InputStart(action);

        }
        public void Perform(string name, InteractionType interactionType = InteractionType.None)
        {
            var action = GetAction(name, false);
            if (action == null) return;
            action._interactionType = interactionType;
            action.Perform();
            _context.InputPerform(action);
        }
        public void Cancel(string name, InteractionType interactionType = InteractionType.None)
        {
            var action = GetAction(name, false);
            if (action == null) return;
            action._interactionType = interactionType;
            action.Cancel();
            _context.InputCancel(action);
        }
        public void Update(float deltaTime)
        {

        }
        private InputAction GetAction(string name, bool create = false)
        {
            if (!actions.TryGetValue(name, out var action))
            {
                if (create)
                {
                    action = new InputAction(name, this);
                    actions.Add(name, action);
                }
            }
            return action;
        }
        private InputDeviceName GetDeviceName(string name)
        {
            if (name.Contains(InputDeviceFlag.Mouse) || name.Contains(InputDeviceFlag.Touch))
            {
                return InputDeviceName.Touch;
            }
            if (name.Contains(InputDeviceFlag.XInput))
            {
                return InputDeviceName.Xbox;
            }
            else if (name.Contains(InputDeviceFlag.DualShock))
            {
                return InputDeviceName.PlayStation;
            }
            else if (name.Contains(InputDeviceFlag.NPad))
            {
                return InputDeviceName.Switch;
            }
#if UNITY_ANDROID || Unity_IOS
            return InputDeviceName.Touch;
#else
            return InputDeviceName.Keyboard;
#endif


        }
        private InputDeviceType GetDeviceType(InputDeviceName name)
        {
            if (name == InputDeviceName.Touch)
            {
                return InputDeviceType.Touch;
            }
            else if (name == InputDeviceName.None)
            {
                return InputDeviceType.None;
            }
            else if (name == InputDeviceName.Xbox || name == InputDeviceName.PlayStation || name == InputDeviceName.Switch)
            {
                return InputDeviceType.Gamepad;
            }
            else
            {
                return InputDeviceType.Keyboard;
            }
        }
    }

    public class InputAction
    {
        private static int _id = 1;
        public const int PHASE_START = 1;
        public const int PHASE_PERFORM = 2;
        public const int PHASE_CANCEL = 3;
        public readonly string name;
        public readonly InputDevice device;
        public int Id { get; private set; }
        public int phase { get; private set; }
        public float value { get { return _value; } }
        public Vector2 value2 { get { return _value2; } }
        public Vector3 value3 { get { return _value3; } }
        public float startTime { get; private set; }
        public float time { get; private set; }
        public InteractionType InteractionType { get { return _interactionType; } }

        internal float _value;
        internal Vector2 _value2;
        internal Vector3 _value3;
        internal InteractionType _interactionType;
        internal List<VirtualInteraction> _interactions;
        internal float _holdIntervalTime;
        internal float _holdTime;
        internal bool _active;
        public InputAction(string name, InputDevice device)
        {
            this.name = name;
            this.device = device;
            this.Id = _id++;
            _interactions = new List<VirtualInteraction>();
        }
        public void Start()
        {
            startTime = Time.time;
            time = startTime;
            phase = PHASE_START;
            _holdTime = 0;
            _active = true;
        }
        public void Perform()
        {
            time = Time.time;
            phase = PHASE_PERFORM;
        }
        public void Cancel()
        {
            time = Time.time;
            phase = PHASE_CANCEL;
            _active = false;
            //不一定触发
        }
        internal bool UpdateHold(float deltaTime)
        {
            if (_holdIntervalTime <= 0f)
            {
                return false;
            }
            _holdTime += deltaTime;
            if (_holdTime > _holdIntervalTime)
            {
                _holdTime -= _holdIntervalTime;
                return true;
            }
            return false;
        }
    }
    public enum InteractionType
    {
        None,
        Hold,
        MultiTap,
        SlowTap,
        Tap,
        Press,
        Release,
        PressAndRelease,
    }
    public class VirtualInteraction
    {
        internal InputAction Action;
        protected bool _cancel;
        protected bool _success;
        protected bool _finished;
        internal InteractionType InteractionType;
        public VirtualInteraction()
        {

        }
        internal virtual VirtualInteraction Clone()
        {
            return new VirtualInteraction();
        }
        public virtual void Update(float deltaTime)
        {

        }
        public virtual void Start()
        {
        }
        public virtual void Stop()
        {

        }

        public virtual bool NeedPerform()
        {
            return false;
        }
        public virtual bool NeedCancel()
        {
            return false;
        }
        public virtual bool IsFinished()
        {
            return true;
        }
        public virtual void Dispose()
        {
            _success = false;
            _finished = false;
            _cancel = false;
        }
    }
    public class VirtualInteractionHold : VirtualInteraction
    {
        //按住到时间
        private float _holdTime = 0.8f;
        private float _time;
        public void Config(float holdTime)
        {
            _holdTime = holdTime;
            InteractionType = InteractionType.Hold;
        }
        internal override VirtualInteraction Clone()
        {
            var v = new VirtualInteractionHold();
            v.Config(_holdTime);
            return v;
        }
        public override void Dispose()
        {
            base.Dispose();
            _time = 0;
        }
        public override void Start()
        {
            base.Start();
            _success = false;
            _time = 0;
            _finished = false;
            _cancel = false;
        }
        public override void Stop()
        {
            base.Stop();
            _cancel = _time < _holdTime;
            _finished = true;
        }
        public override void Update(float deltaTime)
        {
            base.Update(deltaTime);
            _time += deltaTime;
            if (_time > _holdTime)
            {
                _success = true;
                _finished = true;
            }
        }
        public override bool NeedPerform()
        {
            if (_success)
            {
                _success = false;
                return true;
            }
            return false;
        }
        public override bool NeedCancel()
        {
            return _cancel;
        }
        public override bool IsFinished()
        {
            return _finished;
        }

    }
    public class VirtualInteractionMultiTap : VirtualInteraction
    {
        private int TapCount = 2;
        private float TapSpacingTime = 0.4f;
        private int _count = 0;
        private float _time;
        //达到次数和时间间隔条件
        public void Config(int tapCount, float tapSpacingTime)
        {
            this.TapCount = tapCount;
            this.TapSpacingTime = tapSpacingTime;
            InteractionType = InteractionType.MultiTap;
        }
        internal override VirtualInteraction Clone()
        {
            var v = new VirtualInteractionMultiTap();
            v.Config(TapCount, TapSpacingTime);
            return v;
        }
        public override void Dispose()
        {
            base.Dispose();
            _time = 0;
            _count = 0;
        }
        public override void Start()
        {
            base.Start();
            _time = 0f;
            _success = false;
        }
        public override void Stop()
        {
            base.Stop();
            if (_time < TapSpacingTime)
            {
                _count++;
                if (_count >= TapCount)
                {
                    _success = true;
                    _finished = true;
                    _count = 0;
                }
            }
            else
            {
                _cancel = true;
                _finished = true;
            }
        }
        public override void Update(float deltaTime)
        {
            base.Update(deltaTime);
            _time += deltaTime;
        }
        public override bool NeedPerform()
        {
            if (_success)
            {
                _success = false;
                return true;
            }
            return false;
        }
        public override bool NeedCancel()
        {
            if (_cancel)
            {
                _cancel = false;
                return true;
            }
            return false;
        }
        public override bool IsFinished()
        {
            if (_finished)
            {
                return true;
            }
            return false;
        }
    }
    public class VirtualInteractionPress : VirtualInteraction
    {
        internal override VirtualInteraction Clone()
        {
            var v = new VirtualInteractionPress();
            v.InteractionType = this.InteractionType;
            return v;
        }
        public void Config(InteractionType interactionType)
        {
            if (interactionType == InteractionType.Release)
            {
                this.InteractionType = InteractionType.Release;
            }
            else if (interactionType == InteractionType.PressAndRelease)
            {
                this.InteractionType = InteractionType.PressAndRelease;
            }
            else
            {
                this.InteractionType = InteractionType.Press;
            }
        }
        public override void Start()
        {
            base.Start();
            if (this.InteractionType == InteractionType.Press)
            {
                _success = true;
                _finished = true;
            }
            else if (InteractionType == InteractionType.PressAndRelease)
            {
                _success = true;
            }
        }
        public override void Stop()
        {
            base.Stop();
            if (this.InteractionType == InteractionType.Release || InteractionType == InteractionType.PressAndRelease)
            {
                _success = true;
                _finished = true;
            }
        }
        public override bool NeedPerform()
        {
            if (_success)
            {
                _success = false;
                return true;
            }
            return false;
        }
        public override bool IsFinished()
        {
            return _finished;
        }
        public override bool NeedCancel()
        {
            return false;
        }
    }
    public class VirtualInteractionSlowTap : VirtualInteraction
    {
        private float _miniTime;
        private float _time;
        //按住设置时间后松开时
        public void Config(float minTapTime)
        {
            _miniTime = minTapTime;
            InteractionType = InteractionType.SlowTap;
        }
        internal override VirtualInteraction Clone()
        {
            var v = new VirtualInteractionSlowTap();
            v.Config(_miniTime);
            return v;
        }
        public override void Start()
        {
            base.Start();
            _time = 0f;
        }
        public override void Update(float deltaTime)
        {
            base.Update(deltaTime);
            _time += deltaTime;
        }
        public override void Stop()
        {
            base.Stop();
            _finished = true;
            if (_time < _miniTime)
            {
                _cancel = true;
            }
            else
            {
                _success = true;
            }
        }
        public override bool NeedCancel()
        {
            return _cancel;
        }
        public override bool NeedPerform()
        {
            return _success;
        }
        public override bool IsFinished()
        {
            return _finished;
        }
    }
    public class VirtualInteractionTap : VirtualInteraction
    {
        private float _maxTime;
        private float _time;
        //设定时间内松开
        public void Config(float maxTapTime)
        {
            _maxTime = maxTapTime;
            InteractionType = InteractionType.Tap;
        }
        internal override VirtualInteraction Clone()
        {
            var v = new VirtualInteractionTap();
            v.Config(_maxTime);
            return v;
        }
        public override void Start()
        {
            base.Start();
            _time = 0f;
            _finished = false;
            _success = false;
            _cancel = false;
        }
        public override void Update(float deltaTime)
        {
            base.Update(deltaTime);
            _time += deltaTime;
            if (_time > _maxTime)
            {
                _finished = true;
                _cancel = true;
            }
        }
        public override void Stop()
        {
            base.Stop();
            _finished = true;
            _success = _time < _maxTime;
        }
        public override bool NeedPerform()
        {
            return _success;
        }
        public override bool NeedCancel()
        {
            return _cancel;
        }
        public override bool IsFinished()
        {
            return _finished;
        }
    }
}